package com.linciping.useges.plugin.asyc;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vfs.VirtualFile;
import com.linciping.useges.plugin.bean.ModuleInfo;
import com.linciping.useges.plugin.bean.UsegesNode;
import com.linciping.useges.plugin.search.UsegesFilter;
import com.linciping.useges.plugin.util.AsyncUtil;
import com.linciping.useges.plugin.util.ProjectFileUtil;
import com.linciping.useges.plugin.util.PsiFileUtil;
import com.linciping.useges.plugin.view.UsegesModel;
import com.linciping.useges.plugin.view.UsegesWindowUtil;

import java.util.ArrayList;
import java.util.List;

public class ModuleSourceUsegesThread implements Runnable {

    private final Project project;
    private final Module targetModule;
    private final List<VirtualFile> targetModuleSourceFileList;
    private UsegesNode rootNode;

    public ModuleSourceUsegesThread(Project project, Module targetModule, List<VirtualFile> targetModuleSourceFileList) {
        this.project = project;
        this.targetModule = targetModule;
        this.targetModuleSourceFileList = targetModuleSourceFileList;
    }


    @Override
    public void run() {
        List<UsegesNode> sourceNodeList = new ArrayList<>();
        try {
            rootNode = ReadAction.compute((ThrowableComputable<UsegesNode, Throwable>) () -> ProjectFileUtil.createSourceNode(project, targetModule, targetModuleSourceFileList, sourceNodeList, false));
            List<ModuleInfo> sourceRoots = ProjectFileUtil.getProjectSourceList(project, module -> {
                if (ProjectFileUtil.moduleIsProject(module)) {
                    return false;
                }
                if (!ProjectFileUtil.hasDependencies(ModuleRootManager.getInstance(module).getDependencies(), targetModule)) {
                    return false;
                }
                return !module.equals(targetModule);
            }, false, true);
            String rootPackageName = ProjectFileUtil.getRootPackageName(rootNode);
            final UsegesFilter usegesFilter = new UsegesFilter(rootPackageName);
            if (!singleForeach(sourceNodeList.get(0), usegesFilter, sourceRoots)) {
                return;
            }
            sourceNodeList.remove(1);
            for (UsegesNode sourceNode : sourceNodeList) {
                String query = PsiFileUtil.getFullName(sourceNode);
                if (query != null && !query.isEmpty()) {
                    usegesFilter.updateQuery(query);
                    for (ModuleInfo moduleInfo : sourceRoots) {
                        ProjectFileUtil.createUsegesNodeByModule(project, moduleInfo, sourceNode, usegesFilter);
                    }
                }
            }
        } catch (Throwable e) {
            return;
        }
//        AsyncUtil.poolExecute(sourceNodeList, data -> {
//            for (UsegesNode sourceNode : data) {
//                String query = PsiFileUtil.getFullName(sourceNode);
//                if (query != null && !query.isEmpty()) {
//                    usegesFilter.updateQuery(query);
//                    for (ModuleInfo moduleInfo : sourceRoots) {
//                        ProjectFileUtil.createUsegesNodeByModule(project, moduleInfo, sourceNode, usegesFilter);
//                    }
//                    usegesFilter.firstForeachEnd();
//                }
//            }
//            return true;
//        });
        ApplicationManager.getApplication().invokeLater(() -> {
            UsegesModel usegesModel = new UsegesModel(rootNode);
            UsegesWindowUtil.showUsegesWindow(project, usegesModel);
        });
    }

    private boolean singleForeach(UsegesNode usegesNode, UsegesFilter usegesFilter, List<ModuleInfo> sourceRoots) {
        String query = PsiFileUtil.getFullName(usegesNode);
        if (query != null && !query.isEmpty()) {
            usegesFilter.updateQuery(query);
            if (!AsyncUtil.poolForeachModule(sourceRoots, usegesNode, usegesFilter)) {
                return false;
            }
            usegesFilter.firstForeachEnd();
        }
        return true;
    }
}
